package com.sea.base.dialog

import android.app.Dialog
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import android.widget.FrameLayout
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.ActivityResultRegistry
import androidx.activity.result.contract.ActivityResultContract
import androidx.annotation.StyleRes
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner
import com.sea.base.R
import com.sea.base.ext.global.getCurrentMillis
import com.sea.base.ext.global.throwIfDebug
import com.sea.base.ext.obs.lifecycleEventObserver
import com.sea.base.ext.view.FrameLayoutLayoutParams
import com.sea.base.ext.view.MATCH_PARENT
import com.sea.base.ext.view.WRAP_CONTENT
import com.sea.base.ext.view.requireActivity
import com.sea.base.ext.view.requireRootView
import com.sea.base.ext.view.setPaddingOtherDefault
import com.sea.base.ui.IUIContext

/**
 * Dialog：用于弹出式窗口
 *
 * 当前解决的问题：
 * 1.支持根布局gravity、margin、layout属性，解决布局不一致需要手动设置的问题
 * 2.绑定activity生命周期，解决未dismiss问题
 * 3.自带生命周期，解决其他对象对Dialog生命周期的感知的问题
 * 4.自带VM，解决与activity共享VM的问题
 * 5.对show前进行生命周期校验
 * 6.实现了ui接口，可一直套娃
 */
abstract class BaseDialog(
    ui: com.sea.base.ui.IUIContext,
    @StyleRes themeResId: Int = R.style.CustomDialog
) : Dialog(ui.requireActivity, themeResId), LifecycleOwner, ViewModelStoreOwner,
    com.sea.base.ui.IUIContext {

    private val viewModelStore = ViewModelStore()

    private val mLifecycleRegistry = LifecycleRegistry(this)

    private val attachedLifecycleObs = lifecycleEventObserver { _, event ->
        when (event) {
            Lifecycle.Event.ON_RESUME -> {
                if (isShowing) {
                    if (lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) {
                        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
                    }
                }
            }

            Lifecycle.Event.ON_PAUSE -> {
                if (isShowing) {
                    if (lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) {
                        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
                    }
                }
            }

            Lifecycle.Event.ON_STOP -> {
                if (isShowing) {
                    if (lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) {
                        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
                    }
                }
            }

            Lifecycle.Event.ON_DESTROY -> {
                dismiss()
                if (lifecycle.currentState != Lifecycle.State.INITIALIZED) {
                    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
                }
            }

            else -> {}
        }
    }

    private var lastShowMillis = 0L

    val parentUI = ui

    var view: View? = null
        private set

    var isCancelable = true
        private set

    var isCanceledOnTouchOutside = true
        private set

    var dimAmount = 0.4f
        set(value) {
            field = value
            window.setDimAmount(field)
        }

    @StyleRes
    var animStyle = 0
        set(value) {
            field = value
            window.setWindowAnimations(field)
        }

    var isCreated = false
        private set

    /**
     * 防误触模式：在show时的500ms内不会被用户dismiss掉
     * 如果开启此模式，建议你的x号调用[cancel]或者自己校验[isPocketing]而不是直接调用[dismiss]
     * 使用场景：广告弹窗、提醒弹窗等
     */
    var isPocketMode = false

    /**
     * 是否正在防误触时间段中
     */
    val isPocketing get() = isPocketMode && getCurrentMillis() - lastShowMillis < 500L

    init {
        //设置基本默认值
        dimAmount = dimAmount
        animStyle = animStyle
        bindOtherLifecycle(parentUI.lifecycle)
    }

    final override fun onCreate(savedInstanceState: Bundle?) {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
        super.onCreate(savedInstanceState)

        view = createRootView(FrameLayout(context))
        requireRootView.isClickable = true

        onCreate()

        //复原xml的布局效果
        val proxyLp = requireRootView.layoutParams as FrameLayoutLayoutParams
        window.setContentView(view, FrameLayoutLayoutParams(proxyLp.width, proxyLp.height))
        val wlp: WindowManager.LayoutParams = window.attributes
        when (proxyLp.width) {
            WRAP_CONTENT, MATCH_PARENT -> {
                wlp.width = proxyLp.width
            }
        }
        when (proxyLp.height) {
            WRAP_CONTENT, MATCH_PARENT -> {
                wlp.height = proxyLp.height
            }
        }
        wlp.gravity = proxyLp.gravity
        //由于margin暂时没有好的处理（wlp里没有上下左右margin），现直接放在parent的padding里
        val parent = requireRootView.parent as ViewGroup
        parent.setPaddingOtherDefault(
            start = proxyLp.marginStart,
            top = proxyLp.topMargin,
            end = proxyLp.marginEnd,
            bottom = proxyLp.bottomMargin
        )
        //padding会有空白，这里设置点击事件
        parent.setOnClickListener {
            if (isCanceledOnTouchOutside && isCancelable) {
                dismiss()
            }
        }
        window.attributes = wlp

        isCreated = true
    }

    override fun show() {
        if (isShowing) return

        lastShowMillis = getCurrentMillis()

        //create是在之后，无法用create状态判断
        if (!parentUI.lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
            "无法show，当前state：${parentUI.lifecycle.currentState}".throwIfDebug()
            return
        }
        super.show()

        if (parentUI.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
            mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
        }
    }

    override fun setCancelable(flag: Boolean) {
        isCancelable = flag
        super.setCancelable(flag)
    }

    override fun setCanceledOnTouchOutside(cancel: Boolean) {
        isCanceledOnTouchOutside = cancel
        super.setCanceledOnTouchOutside(cancel)
    }

    /**
     * @param inflateLayout 这个Layout不是parent，仅适合用于inflate
     */
    protected abstract fun createRootView(inflateLayout: FrameLayout): View

    protected abstract fun onCreate()

    override fun onStart() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
        super.onStart()
    }

    override fun cancel() {
        //防误触模式
        if (isPocketing) return
        forceCancel()
    }

    open fun forceCancel() {
        super.cancel()
    }

    override fun dismiss() {
        if (isShowing) {
            if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
                mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
            }
        }
        super.dismiss()
    }

    override fun onStop() {
        if (lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) {
            mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
        }
        super.onStop()
    }

    /**
     * 在23以下可能为null，23及以上是直接new的不可能为null
     */
    override fun getWindow(): Window {
        return super.getWindow()!!
    }

    /**
     * 关联其它的lifecycle 关联的页面关闭，同时会触发dialog的dismiss
     */
    fun bindOtherLifecycle(lifecycle: Lifecycle) {
        lifecycle.addObserver(attachedLifecycleObs)
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////
    // UIContext的实现
    /////////////////////////////////////////////////////////////////////////////////////////////////
    override val isFinished get() = parentUI.isFinished
    override fun getActivity() = parentUI.activity

    /**
     * 暂时使用activity的
     */
    override val currentFragmentManager get() = parentUI.currentFragmentManager
    override val rootView get() = view
    override val realDelegate get() = this

    override fun requireViewLifecycle() = lifecycle

    override fun viewLifecycleWithCallback(run: (Lifecycle?) -> Unit) {
        run.invoke(lifecycle)
    }

    override fun startActivity(intent: Intent, options: Bundle?) =
        parentUI.startActivity(intent, options)

    override fun startActivityForResult(intent: Intent, requestCode: Int, options: Bundle?) =
        parentUI.startActivityForResult(intent, requestCode, options)

    override fun <I, O> registerForActivityResult(
        contract: ActivityResultContract<I, O>,
        callback: ActivityResultCallback<O>
    ): ActivityResultLauncher<I> =
        parentUI.registerForActivityResult(contract, callback)

    override fun <I, O> registerForActivityResult(
        contract: ActivityResultContract<I, O>,
        registry: ActivityResultRegistry,
        callback: ActivityResultCallback<O>
    ): ActivityResultLauncher<I> =
        parentUI.registerForActivityResult(contract, registry, callback)

    override fun getLifecycle() = mLifecycleRegistry

    override fun getViewModelStore() = viewModelStore
}